home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 276-300 / 299 / rxil / src / check_port.c < prev    next >
C/C++ Source or Header  |  1995-03-14  |  9KB  |  426 lines

  1. /*   check_port.c        */
  2.  
  3. /*        Copyright © 1989 by Donald T. Meyer, Stormgate Software
  4.  *        All Rights Reserved
  5.  */
  6.  
  7.  
  8.  
  9. #include "rxil.h"
  10.  
  11. #include <string.h>
  12.  
  13.  
  14.  
  15. static void handle_message( struct RexxMsg *rexxmsg );
  16. static void handle_rexx_message( struct RexxMsg *rexxmsg );
  17. static void handle_return( struct RxilInvocation *rxi );
  18.  
  19. static int parse_inplace( char *p, char **argptr, int maxargs );
  20.  
  21.  
  22.  
  23. /*------------------------------------------------------------------*/
  24. /*                    Functions                                        */
  25. /*------------------------------------------------------------------*/
  26.  
  27. /* NAME
  28.  *        RxilCheckPort
  29.  *
  30.  * SYNOPSIS
  31.  *        RxilCheckPort();
  32.  *
  33.  * FUNCTION
  34.  *        Called by the client program's eventloop upon recieving a message
  35.  *        at one of the ports.
  36.  *        This handles the dispatching ( via RxilDispatch() ) of ARexx
  37.  *        commands, the launching of "looped back" macros, and receiving
  38.  *        the replys to macro invocation messages which we have sent to
  39.  *        Rexxmaster.
  40.  *
  41.  *        This is a "safe" call in that if the ARexx library was unopened
  42.  *        or the port opening failed, nothing will go boom!
  43.  *
  44.  * INPUTS
  45.  *        None
  46.  *
  47.  * RESULT
  48.  *        None
  49.  *
  50.  * SIDES
  51.  *
  52.  * HISTORY
  53.  *        01-Aug-89    Creation.
  54.  *        18-Nov-89    Changed an (incorrect) error return code in line 212.
  55.  *
  56.  * BUGS
  57.  *
  58.  * SEE ALSO
  59.  *        RxilInit(), RxilDispatch()
  60.  */
  61.  
  62. void RxilCheckPort( void )
  63. {
  64.     struct RexxMsg *rexxmsg;
  65.  
  66.  
  67.     /* Make call "safe" even if RxilInit() failed */
  68.     if( global_rdef == NULL )
  69.     {
  70.         return;
  71.     }
  72.  
  73.  
  74.     if( RxilCheckCancel() == TRUE )
  75.     {
  76.         /* It would appear that a cancel requester was posted, and
  77.          * the user clicked it!
  78.          */
  79.         RxilCancel();
  80.     }
  81.  
  82.  
  83.     if( global_rdef->SecretPort )
  84.     {
  85.         while(  rexxmsg = (struct RexxMsg *)
  86.             GetMsg( global_rdef->SecretPort )  )
  87.         {
  88.             global_rdef->FromRexx = RXIL_SECRET;
  89.             handle_message( rexxmsg );
  90.             global_rdef->FromRexx = 0;
  91.         }
  92.     }
  93.  
  94.     if( global_rdef->PublicPort )
  95.     {
  96.         while( rexxmsg = (struct RexxMsg *)
  97.             GetMsg( global_rdef->PublicPort ) )
  98.         {
  99.             global_rdef->FromRexx = RXIL_PUBLIC;
  100.             handle_message( rexxmsg );
  101.             global_rdef->FromRexx = 0;
  102.         }
  103.     }
  104.  
  105.  
  106.     /* Do we want to clear the Abort flag? */
  107.  
  108.     if( RxilPending() == FALSE )
  109.     {
  110.         if( global_rdef->CReq != NULL )
  111.         {
  112.             RxilEndCancel();
  113.         }
  114.  
  115.         if(  FlagIsClear( global_rdef->Flags, RXIL_NO_CLEARABORT )  )
  116.         {
  117.             global_rdef->Abort = FALSE;
  118.         }
  119.     }
  120. }
  121.  
  122.  
  123.  
  124. /* This routine is called with the message received at any rexx port.
  125.  * These messages will be of two broad classes.
  126.  * The first is a reply from a command or function which we invoked
  127.  * by sending a packet to RexxMaster.
  128.  *
  129.  * The second is a command sent to our application by an ARexx
  130.  * program.  This could potentialy be from the public port or from
  131.  * the uniquely-named private port.
  132.  */
  133.  
  134. static void handle_message( struct RexxMsg *rexxmsg )
  135. {
  136.     struct RxilInvocation *rxi;
  137.  
  138.  
  139.     /* Decide if it is a reply */
  140.  
  141.     for( rxi=global_rdef->Invocations; rxi; rxi=rxi->Next )
  142.     {
  143.         /* Is this an invocation reply? */
  144.         if( rexxmsg == rxi->RexxMsg )
  145.         {
  146.             /* Yes */
  147.             handle_return( rxi );
  148.             return;
  149.         }
  150.     }
  151.  
  152.  
  153.     /* Apparently not a completion message.  Should be a command
  154.      * from a Rexx program.
  155.      */
  156.  
  157.     if( IsRexxMsg(rexxmsg) == FALSE )
  158.     {
  159.         /* This message is not from ARexx.  Don't touch it,
  160.          * just Reply() it and return.
  161.          */
  162.         ReplyMsg( (struct Message *)rexxmsg );
  163.         return;
  164.     }
  165.  
  166.  
  167.     /* The message is from an ARexx program */
  168.  
  169.     handle_rexx_message( rexxmsg );
  170. }
  171.  
  172.  
  173.  
  174. /* This will take a command message received from an ARexx program
  175.  * and handle the dispatching and replying.
  176.  * This message MUST be from an ARexx program!
  177.  */
  178.  
  179. static void handle_rexx_message( struct RexxMsg *rexxmsg )
  180. {
  181.     char *cmdbuf;
  182.     struct RxilInvocation *child_rxi;
  183.  
  184.  
  185.     /* Default to okay code. */
  186.     rexxmsg->rm_Result1 = RC_OK;
  187.     rexxmsg->rm_Result2 = 0;
  188.  
  189.  
  190.     /* Are we still open for business? */
  191.     if( global_rdef->Abort == TRUE )
  192.     {
  193.         /* Nope! */
  194.         rexxmsg->rm_Result1 = RXERR_ABORTED;
  195.         ReplyMsg( (struct Message *)rexxmsg );
  196.         return;
  197.     }
  198.  
  199.  
  200.     /* Handle the message contents */
  201.  
  202.     /* Just to be squeaky clean, since Bill says to affect only the
  203.      * result fields, copy this into a buffer before parsing.
  204.      *
  205.      * NOTE: Even though an Argstring can by definition contain    
  206.      * embedded null's, the command line is treated as though it
  207.      * were null terminated.
  208.      */
  209.     cmdbuf = AllocMem(  strlen( ARG0(rexxmsg) )+1, 0  );
  210.     if( cmdbuf == NULL )
  211.     {
  212.         rexxmsg->rm_Result1 = RXERR_NO_MEMORY;
  213.         return;
  214.     }
  215.  
  216.     strcpy( cmdbuf, ARG0(rexxmsg) );
  217.  
  218.     /* Parse the command string */
  219.     global_rdef->ArgCount =
  220.         parse_inplace( cmdbuf, &(global_rdef->Arg[0]), RXIL_MAX_ARGS );
  221.  
  222.     if( global_rdef->ArgCount == 0 )
  223.     {
  224.         rexxmsg->rm_Result1 = RXERR_UNKNOWN_CMD;
  225.         FreeMem(  cmdbuf, strlen( ARG0(rexxmsg) )  );
  226.         return;
  227.     }
  228.  
  229.     RxilDispatch( rexxmsg, global_rdef->Arg[0] );
  230.  
  231.     FreeMem(  cmdbuf, strlen( ARG0(rexxmsg)+1 )  );
  232.  
  233.  
  234.     /* Look at macro loopback */
  235.  
  236.     if(  ( rexxmsg->rm_Result1 == RXERR_UNKNOWN_CMD ) &&
  237.         FlagIsClear( global_rdef->Flags, RXIL_NOLAUNCH )  )
  238.     {
  239.         /* Unknown command.  Try to launch it as an ARexx macro. */
  240.         child_rxi = RxilCreateRxi(  ARG0(rexxmsg), RXCOMM  );
  241.  
  242.         if( child_rxi != NULL )
  243.         {
  244.             if(  FlagIsSet( rexxmsg->rm_Action, RXFF_RESULT )  )
  245.             {
  246.                 SetFlag( child_rxi->ActionFlags, RXFF_RESULT );
  247.             }
  248.  
  249.             child_rxi->Parent = rexxmsg;
  250.  
  251.             if(  RxilLaunch( child_rxi ) == 0  )
  252.             {
  253.                 /* Launched successfully */
  254.                 return;            /* Return without replying */
  255.             }
  256.             else
  257.             {
  258.                 /* Launch failure */
  259.                 RxilDeleteRxi( child_rxi );
  260.                 rexxmsg->rm_Result1 = RXERR_FAILED;
  261.             }
  262.         }
  263.         else
  264.         {
  265.             /* Unable to create RxilInvocation structure */
  266.             rexxmsg->rm_Result1 = RXERR_NO_MEMORY;
  267.         }
  268.     }
  269.  
  270.  
  271.     RxilCheckResult( rexxmsg );
  272.  
  273.     ReplyMsg( (struct Message *)rexxmsg );
  274. }
  275.  
  276.  
  277.  
  278. static void handle_return( struct RxilInvocation *rxi )
  279. {
  280.     rxi->State = RXIL_STATE_RETURNED;
  281.  
  282.     if( rxi->CommAddr == global_rdef->SecretPortName )
  283.     {
  284.         /* This implies that the locked flag was set while
  285.          * this ran.  Decrement the lock count.
  286.          */
  287.         --(global_rdef->LockCount);
  288.     }
  289.  
  290.  
  291.     if( rxi->Parent == NULL )
  292.     {
  293.         /* This was originated by the client.  Let the client
  294.          * worry about handling the return and doing the cleanup.
  295.          */
  296.         return;
  297.     }
  298.  
  299.  
  300.     /* This is the return for a program which was "looped" back out
  301.      * to ARexx.
  302.      */
  303.  
  304.     /* Pass thru?? the result */
  305.  
  306.     rxi->Parent->rm_Result1 = rxi->RexxMsg->rm_Result1;
  307.     rxi->Parent->rm_Result2 = rxi->RexxMsg->rm_Result2;
  308.  
  309.     RxilCheckResult( rxi->Parent );
  310.  
  311.  
  312.     /* Reply to the parent */
  313.     ReplyMsg(  (struct Message *)(rxi->Parent)  );
  314.  
  315.  
  316.     /* Cleanup the invocation RexxMsg */
  317.  
  318.     /* Zero these to prevent the cleanup routine from freeing
  319.      * the return Argstring.
  320.      */
  321.     rxi->RexxMsg->rm_Result1 = 0;
  322.     rxi->RexxMsg->rm_Result2 = 0;
  323.  
  324.     /* Clear these to prevent the cleanup routine from closing
  325.      * streams which were inherited from the parent.
  326.      */
  327.     rxi->RexxMsg->rm_Stdin = NULL;
  328.     rxi->RexxMsg->rm_Stdout = NULL;
  329.  
  330.     RxilCleanupReturn( rxi );
  331.  
  332.  
  333.     /* And free the RxilInvocation structure */
  334.     RxilDeleteRxi( rxi );
  335. }
  336.  
  337.  
  338.  
  339. /* This is intended to be a very memory efficient parsing procedure.
  340.  * The length of the options is limited only by the length of the
  341.  * input line buffer (owned by the caller).  The number of arguments which
  342.  * can be parsed out of an input string is limited by the size of the
  343.  * pointer array, which is also owned by the caller.
  344.  * Note that this WILL MODIFY the contents of the line passed in the
  345.  * buffer.  If this is un-desirable, copy the string to a scratch buffer
  346.  * and pass that.
  347.  *
  348.  * The calling should look something like:
  349.  *        char *myargpointers[10];
  350.  *        int myargcount;
  351.  *        char buf[100];
  352.  *
  353.  *        gets( buf );
  354.  *        myargcount = inplace_parse( buf, myargpointers, 10 );
  355.  */
  356.  
  357. static int parse_inplace( char *p, char **argptr, int maxargs )
  358. {
  359.     BOOL inparen = FALSE, inarg = FALSE;
  360.     char *argstart = 0;        /* Does not really need to be initialized */
  361.     int argcount = 0;
  362.  
  363.  
  364.     while(  (*p != '\0') && (argcount < maxargs)  )
  365.     {
  366.         switch( *p )
  367.         {
  368.             case ' ':
  369.             case '\t':
  370.                 /* Whitespace */
  371.                 if(  (inarg == TRUE) && (inparen == FALSE)  )
  372.                 {
  373.                     /* We got one! */
  374.                     *p = '\0';        /* place a delimiting null */
  375.                     argptr[argcount++] = argstart;
  376.                     inarg = FALSE;
  377.                     inparen = FALSE;
  378.                 }
  379.                 break;
  380.  
  381.             case '"':
  382.                 if( inparen == TRUE )
  383.                 {
  384.                     /* This is closing paren */
  385.                     /* We got one! */
  386.                     *p = '\0';        /* place a delimiting null */
  387.                     argptr[argcount++] = argstart;
  388.                     inarg = FALSE;
  389.                     inparen = FALSE;
  390.                 }
  391.                 else
  392.                 {
  393.                     /* Opening paren */
  394.                     if( inarg == TRUE )
  395.                     {
  396.                         /* Deal with the previous arg first */
  397.                         *p = '\0';        /* place a delimiting null */
  398.                         argptr[argcount++] = argstart;
  399.                     }
  400.  
  401.                     inparen = TRUE;
  402.                     inarg = TRUE;
  403.                     argstart = p+1;
  404.                 }
  405.                 break;
  406.  
  407.             default:
  408.                 /* A character we want in an argument string */
  409.                 if( inarg == FALSE )
  410.                 {
  411.                     inarg = TRUE;
  412.                     argstart = p;
  413.                 }
  414.                 break;
  415.         }
  416.  
  417.         p++;
  418.     }
  419.  
  420.     if(  (inarg == TRUE) && (argcount < maxargs)  )
  421.         argptr[argcount++] = argstart;
  422.  
  423.     return( argcount );
  424. }
  425.  
  426.